#include "mainwindow.h"
#include <ctime>
#include <wx/dir.h>
#include <shapefil.h>
#include <fstream>
#include <thread>
#include <wx/tokenzr.h>

using namespace std;

// 配置文件路径
#define PARSE_FILE              "./settings/fundparse.json"
#define TA_FILE                 "./settings/tacode.ini"
#define TA_CHECK_FILE           "./settings/tacheck.ini"
#define FUNDROMEFILE            "./settings/config.ini" 

// 全局字体信息
#define FONT_SIZE 12
#define FONT_FACE "微软雅黑"

// 基金业务类型
#define REDEEM_TYPE "112"
#define FORCED_REDEEM_TYPE "342"
#define RODUNS_TYPE "343"
#define WINDING_TYPE "350"
#define SUBSCRIPTION "110"
#define PURCHASE "111"
#define REGULAR_PURCHASE "115"
#define FAILED_TO_RAISE "349"

#define FUNDTOPATH "./settlefile/"
#define FUNDFROMPATH "D:/CPP/VSProject/newfund/fundtest/"


// #define EXPORT_FULL


//控件ID
#define BTN_ADD_FUND_ID                         1001
#define BTN_CLEAR_FUND_ID                       1002
#define BTN_EXPORT_FUND_ID                      1003
#define GRID_DELETE_ROW_ID                      1004
#define GRID_WINDOW_ID                          1005
#define TEXT_CTRL_FUND_CODE_INPUT_ID            1006
#define TEXT_CTRL_FUND_NAME_INPUT_ID            1007


mainFrame::mainFrame() : wxFrame(nullptr, wxID_ANY, wxT("wxfund"))
{
    initCheckTaInfo(TA_CHECK_FILE, m_checkInfos);   //初始化数据
    setTaFileFromPath();                            //初始化程序参数
    initData();
    initGUI();
    initEvent();                                    //初始化事件    
}

//初始化GUI
void mainFrame::initGUI()
{

    // 设置字体
    wxFont m_font(wxFontInfo(FONT_SIZE));
    m_font.SetFaceName(wxString(FONT_FACE));
    this->SetFont(m_font);

    // 设置主窗口大小
    SetSize(wxSize(1120, 630));    

    // 设置标题
    SetTitle(wxT("基金参数导出"));

    //设置颜色
    SetOwnBackgroundColour(wxColor("#E3E3E3"));

    // 主布局
    wxBoxSizer *mainSizer = new wxBoxSizer(wxVERTICAL);

    // 第一层布局
    m_staticTextTa = new wxStaticText(this, wxID_ANY, wxT("TA代码"));
    m_choiceTa = new wxChoice(this, wxID_ANY);
    m_staticTextFundCode = new wxStaticText(this, wxID_ANY, wxT("基金代码"));
    m_textCtrlFundCode = new wxTextCtrl(this, wxID_ANY);
    m_textCtrlFundCode->SetId(TEXT_CTRL_FUND_CODE_INPUT_ID);
    m_textCtrlFundCode->SetWindowStyle(wxTE_PROCESS_ENTER);

    // 设置最小宽度
    m_choiceTa->SetMinSize(wxSize(220, -1));
    m_staticTextTa->SetMinSize(wxSize(100, -1));
    m_staticTextFundCode->SetMinSize(wxSize(100, -1));
    m_staticTextTa->SetWindowStyle(wxALIGN_CENTER_HORIZONTAL);
    m_staticTextFundCode->SetWindowStyle(wxALIGN_CENTER_HORIZONTAL);

    wxBoxSizer *firstSizer = new wxBoxSizer(wxHORIZONTAL);
    firstSizer->Add(m_staticTextTa, 0);
    firstSizer->Add(m_choiceTa, 0);
    firstSizer->Add(m_staticTextFundCode, 0);
    firstSizer->Add(m_textCtrlFundCode, 4, wxEXPAND);

    // 第二层布局
    m_staticTextParse = new wxStaticText(this, wxID_ANY, wxT("基金参数"));
    m_choiceParse = new wxChoice(this, wxID_ANY);
    m_staticTextFundName = new wxStaticText(this, wxID_ANY, wxT("基金名称"));
    m_textCtrlFundName = new wxTextCtrl(this, wxID_ANY);
    m_textCtrlFundName->SetId(TEXT_CTRL_FUND_NAME_INPUT_ID);
    m_staticTextParse->SetMinSize(m_staticTextTa->GetMinSize()); // 上下两个控件的大小保持一致
    m_choiceParse->SetMinSize(m_choiceTa->GetMinSize());
    m_staticTextFundName->SetMinSize(m_staticTextFundCode->GetMinSize());
    m_staticTextParse->SetWindowStyle(wxALIGN_CENTER_HORIZONTAL);
    m_staticTextFundName->SetWindowStyle(wxALIGN_CENTER_HORIZONTAL);

    wxBoxSizer *secondSzier = new wxBoxSizer(wxHORIZONTAL);
    secondSzier->Add(m_staticTextParse, 0);
    secondSzier->Add(m_choiceParse, 0);
    secondSzier->Add(m_staticTextFundName, 0);
    secondSzier->Add(m_textCtrlFundName, 1, wxEXPAND);

    // 第三次布局 按钮
    m_buttonAddFund = new wxButton(this, wxID_ANY, wxT("增加基金"));
    m_buttonClearFund = new wxButton(this, wxID_ANY, wxT("删除基金"));
    m_buttonExportFund = new wxButton(this, wxID_ANY, wxT("导出基金"));
    m_buttonAddFund->SetId(BTN_ADD_FUND_ID);
    m_buttonClearFund->SetId(BTN_CLEAR_FUND_ID);
    m_buttonExportFund->SetId(BTN_EXPORT_FUND_ID);

    m_buttonAddFund->SetMinSize(wxSize(150, -1));
    m_buttonClearFund->SetMinSize(wxSize(150, -1));
    m_buttonExportFund->SetMinSize(wxSize(150, -1));

    wxGridSizer *threeSizer = new wxGridSizer(1, 3, wxDefaultSize);
    threeSizer->Add(m_buttonAddFund, 0, wxALIGN_CENTER_HORIZONTAL, 5);
    threeSizer->Add(m_buttonClearFund, 0, wxALIGN_CENTER_HORIZONTAL, 5);
    threeSizer->Add(m_buttonExportFund, 0, wxALIGN_CENTER_HORIZONTAL, 5);

    // 第四次布局 表格
    m_gridFundData = new wxGrid(this, wxID_ANY);
    m_gridFundData->SetId(GRID_WINDOW_ID);

    // Grid
    m_gridFundData->CreateGrid(0, 5);
    m_gridFundData->EnableEditing(true);
    m_gridFundData->EnableGridLines(true);
    m_gridFundData->EnableDragGridSize(false);
    m_gridFundData->SetMargins(0, 0);
    m_gridFundData->SetFont(m_font);
    m_gridFundData->SetLabelFont(m_font);
    m_gridFundData->SetDefaultCellFont(m_font);

    // Columns
    m_gridFundData->EnableDragColMove(false);
    m_gridFundData->EnableDragColSize(true);
    m_gridFundData->SetColLabelSize(30);
    m_gridFundData->SetColLabelValue(0, wxT("TA代码"));
    m_gridFundData->SetColLabelValue(1, wxT("基金代码"));
    m_gridFundData->SetColLabelValue(2, wxT("基金名称"));
    m_gridFundData->SetColLabelValue(3, wxT("赎回天数"));
    m_gridFundData->SetColLabelValue(4, wxT("分红天数"));
    m_gridFundData->SetColLabelAlignment(wxALIGN_CENTER, wxALIGN_CENTER);

    // Rows
    m_gridFundData->EnableDragRowSize(true);
    m_gridFundData->SetRowLabelSize(20);
    m_gridFundData->SetRowLabelAlignment(wxALIGN_CENTER, wxALIGN_CENTER);

    // 设置选择模式(按行选择)
    m_gridFundData->SetSelectionMode(wxGrid::wxGridSelectRows);

    // 设置表格不可编辑
    m_gridFundData->EnableEditing(false);

    // Cell Defaults
    m_gridFundData->SetDefaultCellAlignment(wxALIGN_LEFT, wxALIGN_TOP);
    m_gridFundData->SetFont(m_font);
    wxBoxSizer *fourSizer = new wxBoxSizer(wxVERTICAL);
    fourSizer->Add(m_gridFundData, 1, wxEXPAND, 5);

    mainSizer->AddSpacer(8);
    mainSizer->Add(firstSizer, 0, wxEXPAND);
    mainSizer->AddSpacer(8);
    mainSizer->Add(secondSzier, 0, wxEXPAND);
    mainSizer->AddSpacer(8);
    mainSizer->Add(threeSizer, 0, wxEXPAND);
    mainSizer->AddSpacer(8);
    mainSizer->Add(fourSizer, 1, wxEXPAND | wxTop, 10);
    this->SetSizer(mainSizer);

    // 设置choice数据
    setParseChioceData();
    setTaChioceData();

    // 默认基金代码框为焦点
    m_textCtrlFundCode->SetFocus();  

    Centre(wxBOTH);

    //初始化消息弹窗
    m_MessageDialog = new wxMessageDialog(this,"");
}

//初始化基金确认文件相关数据
void mainFrame::initData()
{
    std::list<std::string> m_c2FundFiles;
    std::list<std::string> m_07FundFiles;
    // 拷贝全部基金文件
    int result;
    auto mItor = m_Settings.find("ta_file_from_path");
    if (mItor == m_Settings.end())
        result = copyfundBusiDatafile(FUNDFROMPATH, FUNDTOPATH);
    else
        result = copyfundBusiDatafile(mItor->second, FUNDTOPATH);
    if (result != 0)
        return;

    // 读取07文件
    get07fileList(FUNDTOPATH, m_07FundFiles);
    for (auto itor = m_07FundFiles.begin(); itor != m_07FundFiles.end(); itor++)
    {
        initfundBusiData07(*itor, m_M07Funds);
    }

    // 读取c2文件
    getC2fileList(FUNDTOPATH, m_c2FundFiles);
    for (auto itor = m_c2FundFiles.begin(); itor != m_c2FundFiles.end(); itor++)
    {
        initfundbusidataC2(*itor, m_Mc2Funds);
    }
}

//设置大小事件
void mainFrame::onSizeEvent(wxSizeEvent &event)
{
    event.Skip();

    int mainWidth = GetSize().GetWidth();
    int rowLableWidth = m_gridFundData->GetRowLabelSize();
    int arvrowLableWidth = (int)(mainWidth - m_gridFundData->GetRowLabelSize() * 2) / 5;
    m_gridFundData->SetColSize(0, arvrowLableWidth);
    m_gridFundData->SetColSize(1, arvrowLableWidth);
    m_gridFundData->SetColSize(2, arvrowLableWidth);
    m_gridFundData->SetColSize(3, arvrowLableWidth);
    m_gridFundData->SetColSize(4, mainWidth - arvrowLableWidth * 4 - rowLableWidth * 2);
    
    // 默认基金代码框为焦点
    m_textCtrlFundCode->SetFocus();
}

//设置选择行删除事件
void mainFrame::onDeleteRow(wxCommandEvent &event)
{
}

//设置基金增加按钮输入框
void mainFrame::onAddfund(wxCommandEvent& event)
{
        event.Skip();
        wxString tfundCode = m_textCtrlFundCode->GetLineText(0).Trim();
        if (tfundCode.length() == 0)
        {
                wxMessageBox(wxT("基金代码为空,请重新输入"), wxT("提示信息"), wxOK | wxICON_ERROR, this);                
                m_textCtrlFundName->Clear();
                m_textCtrlFundCode->SetFocus();
                return;
        }

        // 验证基金代码是否为数字和字母
        const char *charFundCode = tfundCode.c_str();
        for (size_t i = 0; i < strlen(charFundCode); i++)
        {
                if (int(charFundCode[i]) < 48 || int(charFundCode[i]) > 90)
                {
                        wxMessageBox(wxT("输入的基金代码不正确,请重新输入"), wxT("提示信息"), wxOK | wxICON_ERROR, this);
                        m_textCtrlFundCode->Clear();
                        m_textCtrlFundCode->SetFocus();
                        return;
                }
                if (int(charFundCode[i]) > 57 && int(charFundCode[i]) < 65)
                {
                        wxMessageBox(wxT("输入的基金代码不正确,请重新输入"), wxT("提示信息"), wxOK | wxICON_ERROR, this);
                        m_textCtrlFundCode->Clear();
                        m_textCtrlFundCode->SetFocus();
                        return;
                }
        }

        Fund tempfund;
        memset(&tempfund, 0, sizeof(tempfund));

        // 设置代码
        strncpy(tempfund.fund_code, tfundCode.c_str(), 8);

        //检查基金是否已经存在
        for (auto it = m_Funds.begin(); it != m_Funds.end(); it++)
        {
                if (strcmp(it->fund_code, tempfund.fund_code) == 0)
                {
                        wxMessageBox(wxT("输入的基金代码已存在,请重新输入"), wxT("提示信息"), wxOK | wxICON_ERROR, this);
                        m_textCtrlFundCode->Clear();
                        m_textCtrlFundName->Clear();
                        m_textCtrlFundCode->SetFocus();
                        return;
                }
        }

        wxString tempGridFundName;      //表格基金名称
        wxCSConv enCoder(wxFONTENCODING_CP936);
        if (m_choiceTa->GetCurrentSelection() == 0)
        {
                // 取基金名称
                auto T_07itor = m_M07Funds.find(tfundCode.ToStdString());
                if (T_07itor != m_M07Funds.end())
                {
                        // 对基金名称进行处理，删除多余字符，仅保留简称
                        tempGridFundName = wxString(T_07itor->second.c_str(),enCoder);
                        dealFundName(tempGridFundName);
                        strncpy(tempfund.fund_name, tempGridFundName.ToStdString().c_str(), sizeof(tempfund.fund_name) - 1);
                }
                else
                {
                        wxMessageBox(wxT("基金信息文件(07)中没有找到该基金，请通过手工维护"), wxT("错误信息"), wxOK | wxICON_ERROR);
                        return;
                }

                // 取基金参数
                auto T_c2itor = m_Mc2Funds.find(tfundCode.ToStdString());
                if (T_c2itor != m_Mc2Funds.end())
                {
                        // 取TA代码
                        strncpy(tempfund.ta_code, T_c2itor->second.ta_code.c_str(), sizeof(tempfund.ta_code) - 1);
                        // 取OTC交收信息
                        tempfund.otc_fh_date = T_c2itor->second.fh + 1;
                        tempfund.otc_sh_date = T_c2itor->second.sh + 1;
                        // 取法人参数ID
                        int index = 0;
                        bool contentFlag = false;
                        for (auto &item : m_Parse)
                        {

                                if ((item.xy_fh_date == T_c2itor->second.fh) && (item.xy_sh_date == T_c2itor->second.sh))
                                {
                                        contentFlag = true;
                                        break;
                                }
                                index++;
                        }
                        if (contentFlag)
                        {
                                strncpy(tempfund.parse_id, m_Parse[index].parse_id.c_str(), sizeof(tempfund.parse_id) - 1);
                        }
                        else
                        {
                                wxString msg;
                                msg << wxT("参数模板中没有赎回");
                                msg << T_c2itor->second.sh;
                                msg << wxT("分红");
                                msg << T_c2itor->second.fh;
                                msg << wxT("的模板，请手工维护");
                                wxMessageBox(msg, wxT("错误信息"), wxOK | wxICON_ERROR);
                                return;
                        }
                }
                else
                {
                        wxMessageBox(wxT("基金信息文件(C2)中没有找到该基金，请通过手工维护"), wxT("错误信息"), wxOK | wxICON_ERROR);
                        return;
                }
        }
        else
        {
                // 设置基金TA
                strncpy(tempfund.ta_code, m_Tas[m_choiceTa->GetCurrentSelection()].code.c_str(), sizeof(tempfund.ta_code) - 1);

                // 设置基金名称
                tempGridFundName = m_textCtrlFundName->GetLineText(0);
                if (tempGridFundName.length() == 0)
                {
                        wxMessageBox(wxT("基金名称为空,请重新输入"), wxT("提示信息"), wxOK | wxICON_ERROR, this);
                        m_textCtrlFundName->SetFocus();
                        return;
                }

                // 对基金名称进行处理，删除多余字符，仅保留简称
                dealFundName(tempGridFundName);
                strncpy(tempfund.fund_name, tempGridFundName.ToStdString().c_str(), sizeof(tempfund.fund_name) - 1);

                // 检查TA
                if (!fundCheck(tempfund.ta_code, tempfund.fund_name, m_checkInfos))
                {
                        wxString mes;
                        mes.append("基金名称:【");
                        mes.append(tempfund.fund_name);
                        mes.append("】和TA代码:【");
                        mes.append(tempfund.ta_code);
                        mes.append("】可能不匹配，是否继续添加?");
                        auto res = wxMessageBox(mes, wxT("提示信息"), wxYES_NO | wxICON_QUESTION, this);
                        if (res == wxNO)
                                return;
                }

                // 设置基金参数
                strncpy(tempfund.parse_id, m_Parse[m_choiceParse->GetCurrentSelection()].parse_id.c_str(), sizeof(tempfund.parse_id) - 1);
                tempfund.otc_fh_date = m_Parse[m_choiceParse->GetCurrentSelection()].xy_fh_date + 1;
                tempfund.otc_sh_date = m_Parse[m_choiceParse->GetCurrentSelection()].xy_sh_date + 1;
        }

        m_Funds.push_back(tempfund);

        m_gridFundData->AppendRows();
        auto rowNum = m_gridFundData->GetNumberRows();
       
        m_gridFundData->SetCellValue(rowNum - 1, 0, getFullTaName(&m_Tas[m_choiceTa->GetCurrentSelection()]));
        m_gridFundData->SetCellValue(rowNum - 1, 1, tempfund.fund_code);
        m_gridFundData->SetCellValue(rowNum - 1, 2, tempGridFundName);      //定义tempGridFundName修复显示问题
        m_gridFundData->SetCellValue(rowNum - 1, 3, wxString::Format("%i", tempfund.otc_sh_date - 1));
        m_gridFundData->SetCellValue(rowNum - 1, 4, wxString::Format("%i", tempfund.otc_fh_date - 1));

        // 如果是自动获取参数，更新TA代码
        if (m_choiceTa->GetCurrentSelection() == 0)
        {
                string taFullName = tempfund.ta_code;
                for (auto item : m_Tas)
                {
                        if (item.code == taFullName)
                                taFullName = getFullTaName(&item);
                }
                m_gridFundData->SetCellValue(rowNum - 1, 0, taFullName);
        }

        m_gridFundData->SetRowSize(rowNum - 1, 35);

        // 设置滚动条自动滚动至最后
        if (!m_gridFundData->IsVisible(rowNum - 1, 0))
        {
                m_gridFundData->ScrollLines(rowNum);
        }

        // 清空输入框，等待下一次输入
        m_textCtrlFundCode->Clear();
        m_textCtrlFundName->Clear();
        m_textCtrlFundCode->SetFocus();
}

//设置基金清除按钮事件
void mainFrame::onClearFund(wxCommandEvent &event)
{
    if(m_Funds.size()==0)
        return;
    if(!m_gridFundData->IsSelection())
    {
        auto res = wxMessageBox(wxT("将删除全部已录入基金，请确认？"), wxT("基金删除"), wxYES_NO | wxICON_QUESTION, this);
        if (res == wxNO)
            return;
        m_gridFundData->ClearGrid();
        m_gridFundData->DeleteRows(0, m_gridFundData->GetNumberRows());
        m_Funds.clear();
    }else
    {
        auto rowsNum = m_gridFundData->GetSelectedRows();
        for (size_t i = 0; i < rowsNum.size(); i++)
        {
            if (m_gridFundData->GetSelectedRows().size() != 0)
            {
                int firstSelectIndex = m_gridFundData->GetSelectedRows()[0];
                m_Funds.erase(m_Funds.begin() + firstSelectIndex);
                m_gridFundData->DeleteRows(firstSelectIndex);
            }
        }
    }
}

//设置基金导出按钮事件
void mainFrame::onExportFund(wxCommandEvent &event)
{

    m_buttonAddFund->Enable(false);
    m_buttonClearFund->Enable(false);
    m_buttonExportFund->Enable(false);

    if (m_Funds.size() == 0)
    {
        wxMessageBox(wxT("不存在未导出基金"), wxT("文件导出"), wxOK | wxICON_ERROR);
        // 清空输入框，等待下一次输入
        m_textCtrlFundCode->Clear();
        m_textCtrlFundName->Clear();
        m_textCtrlFundCode->SetFocus();
        m_buttonAddFund->Enable(true);
        m_buttonClearFund->Enable(true);
        m_buttonExportFund->Enable(true);
        return;
    }
    if (generateCsv() && generateDbf())
    {
        wxMessageBox(wxT("基金文件导出完成"), wxT("文件导出"), wxOK | wxICON_INFORMATION);
    }
    else
    {
        wxMessageBox(wxT("基金文件导出失败，请重新导出"), wxT("文件导出"), wxOK | wxICON_ERROR);
    }

    m_buttonAddFund->Enable(true);
    m_buttonClearFund->Enable(true);
    m_buttonExportFund->Enable(true);
}

//设置基金名称输入框事件
void mainFrame::onFundNameInput(wxCommandEvent &event)
{
    event.Skip();
    wxString tempFundName = m_textCtrlFundName->GetLineText(0).Trim().Trim(false);
    // 去掉中间的空格
    for (auto itor = tempFundName.begin(); itor != tempFundName.end(); itor++)
    {
        if (*itor == wxChar(' '))
        {
            tempFundName.erase(itor);
            itor--; // 确保字符串第一个字符不为空
        }
    }
    m_textCtrlFundName->ChangeValue(tempFundName);
}

//设置基金代码输入框事件
void mainFrame::onFundCodeInput(wxCommandEvent &event)
{
    event.Skip();
    wxString tempFundCode = m_textCtrlFundCode->GetLineText(0).Trim().Trim(false);
    // 去掉中间的空格
    for (auto itor = tempFundCode.begin(); itor != tempFundCode.end(); itor++)
    {
        if (*itor == wxChar(' '))
        {
            tempFundCode.erase(itor);
            itor--;
        }    
    }
    m_textCtrlFundCode->ChangeValue(tempFundCode);

}

// 设置参数选项
void mainFrame::setParseChioceData()
{
    initParse(PARSE_FILE, m_Parse);
    wxArrayString chioces;
    for (int i = 0; i < m_Parse.size(); i++)
    {
        chioces.push_back(wxString(m_Parse[i].parse_name));
    }
    m_choiceParse->Set(chioces);
    m_choiceParse->SetSelection(0); // 选中第一个
}

// 设置TA选项
void mainFrame::setTaChioceData()
{
    initTaInfo(TA_FILE, m_Tas);
    wxArrayString chioces;
    for (int i = 0; i < m_Tas.size(); i++)
    {
        chioces.push_back(wxString(getFullTaName(&m_Tas[i])));
    }
    m_choiceTa->Set(chioces);
    m_choiceTa->SetSelection(0); // 选中第一个
}

//生成DBF文件
bool mainFrame::generateDbf()
{
    wxString fileName = wxT("./out/fundinfo.dbf");

    if (!wxDir::Exists(wxT("./out")))
    {
        wxDir::Make(wxT("./out"));
    }

#ifdef OUT_FILE_COVER

    当导出文件已经存在时，不覆盖，通过增加文件数字后缀的方式重命名
    if (wxFile::Exists(fileName))
    {
        int fileNum = 1;
        while (wxFile::Exists(fileName))
        {
            fileName = wxString::Format(wxT("./out/fundinfo_%i.dbf"), fileNum++);
        }
    }

#endif

    // 创建DBF
    auto dbfhandle = DBFCreate(fileName.ToStdString().c_str());

    // 检查创建情况
    if (dbfhandle == NULL)
    {
        wxMessageBox(wxT("新意文件导出失败，创建DBF文件句柄失败"), wxT("错误信息"), wxOK | wxICON_ERROR);
        return false;
    }

    // 添加字段
    DBFAddField(dbfhandle, "MODEL_ID", FTString, 10, 0);
    DBFAddField(dbfhandle, "FUND_CODE", FTString, 30, 0);
    DBFAddField(dbfhandle, "FUND_NAME", FTString, 40, 0);
    DBFAddField(dbfhandle, "TA_CODE", FTString, 6, 0);
    DBFAddField(dbfhandle, "CUR_TYPE", FTString, 3, 0);
    DBFAddField(dbfhandle, "IS_CHARGE", FTString, 1, 0);
    DBFAddField(dbfhandle, "FUND_STYLE", FTString, 1, 0);
    DBFAddField(dbfhandle, "FULL_NAME", FTString, 60, 0);
    DBFAddField(dbfhandle, "TA_PUBLISH", FTString, 30, 0);
    DBFAddField(dbfhandle, "DATE_BEG", FTString, 8, 0);
    DBFAddField(dbfhandle, "DATE_END", FTString, 8, 0);
    DBFAddField(dbfhandle, "SETTLEBANK", FTString, 30, 0);
    DBFAddField(dbfhandle, "NOTE", FTString, 255, 0);
    DBFAddField(dbfhandle, "TRADEPLACE", FTString, 1, 0);
    DBFAddField(dbfhandle, "FIRST_DATE", FTString, 8, 0);
    DBFAddField(dbfhandle, "MAIN_FUND", FTString, 30, 0);

    wxString current_date_str = wxDateTime::Now().Format("%Y%m%d");

    // 增加记录
    for (size_t i = 0; i < m_Funds.size(); i++)
    {
        DBFWriteStringAttribute(dbfhandle, i, 0, m_Funds[i].parse_id);
        DBFWriteStringAttribute(dbfhandle, i, 1, m_Funds[i].fund_code);
        DBFWriteStringAttribute(dbfhandle, i, 2, m_Funds[i].fund_name);
        DBFWriteStringAttribute(dbfhandle, i, 3, m_Funds[i].ta_code);
        DBFWriteStringAttribute(dbfhandle, i, 4, "CNY");
        DBFWriteStringAttribute(dbfhandle, i, 5, "0");
        DBFWriteStringAttribute(dbfhandle, i, 6, "0");
        DBFWriteStringAttribute(dbfhandle, i, 7, m_Funds[i].fund_name);
        DBFWriteNULLAttribute(dbfhandle, i, 8);
        DBFWriteStringAttribute(dbfhandle, i, 9, current_date_str.ToStdString().c_str());
        DBFWriteStringAttribute(dbfhandle, i, 10, current_date_str.ToStdString().c_str());
    }
    // 关闭
    DBFClose(dbfhandle);

    // 拷贝文件进行备份，文件以日期和时间为后缀
    if (!wxDir::Exists(wxT("./bak")))
    {
        wxDir::Make(wxT("./bak"));
    }

    // 备份文件
    char timeStr[128];
    time_t currentTime = time(NULL);
    strftime(timeStr, 128, "%Y-%m-%d-%H-%M-%S", localtime(&currentTime));
    wxCopyFile(fileName, wxString(wxT("./bak/fundinfo_")).append(timeStr).append(wxT(".dbf")), true);
    return true;
}

//生成CSV文件
bool mainFrame::generateCsv()
{
    wxString fileName = wxT("./out/fundinfo.csv");
    std::string csvFileName = "./out/fundinfo.csv";

    if (!wxDir::Exists(wxT("./out")))
    {
        wxDir::Make(wxT("./out"));
    }
    std::ofstream outFile;
    outFile.open("./out/fundinfo.csv", std::ios::out);
    if (outFile.fail())
    {
        wxMessageBox(wxT("OTC文件导出失败\n\n fundinfo.csv文件打开失败"), wxT("CSV文件导出"), wxOK | wxICON_ERROR);
        return false;
    }
    outFile << "产品编码"
            << ",";
    outFile << "交易类别"
            << ",";
    outFile << "清算方式"
            << ",";
    outFile << "DVP交收标志"
            << ",";
    outFile << "担保交收标志"
            << ",";
    outFile << "资金交收天数"
            << ",";
    outFile << "份额交收天数"
            << ",";
    outFile << "资金可用天数"
            << ",";
    outFile << "份额可用天数"
            << ",";
    outFile << "结算币种"
            << ",";
    outFile << "清算模式"
            << ",";
    outFile << "资金交收标志"
            << ",";
    outFile << "赎回资金处理方式"
            << ",";
    outFile << std::endl;

    for (const auto &item : m_Funds)
    {
        // 增加赎回
        outFile << "\t" << item.fund_code << ",";
        outFile << "\t" << REDEEM_TYPE << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t" << item.otc_sh_date << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t" << item.otc_sh_date << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "2"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "0"
                << "," << std::endl;

        // 增加强赎
        outFile << "\t" << item.fund_code << ",";
        outFile << "\t" << FORCED_REDEEM_TYPE << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t" << item.otc_sh_date << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t" << item.otc_sh_date << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "2"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "0"
                << "," << std::endl;

        // 增加清盘
        outFile << "\t" << item.fund_code << ",";
        outFile << "\t" << WINDING_TYPE << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t" << item.otc_sh_date << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t" << item.otc_sh_date << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "2"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "0"
                << "," << std::endl;

        // 增加分红
        outFile << "\t" << item.fund_code << ",";
        outFile << "\t" << RODUNS_TYPE << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t" << item.otc_fh_date << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t" << item.otc_fh_date << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "2"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "0"
                << "," << std::endl;

        #ifdef EXPORT_FULL

        // 增加认购
        outFile << "\t" << item.fund_code << ",";
        outFile << "\t" << SUBSCRIPTION << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << std::endl;

        // 设置申购
        outFile << "\t" << item.fund_code << ",";
        outFile << "\t" << PURCHASE << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << std::endl;

        // 设置定时定额申购
        outFile << "\t" << item.fund_code << ",";
        outFile << "\t" << REGULAR_PURCHASE << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << std::endl;

        // 设置募集失败
        outFile << "\t" << item.fund_code << ",";
        outFile << "\t" << FAILED_TO_RAISE << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "2"
                << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "2"
                << ",";
        outFile << "\t"
                << "1"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "2"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << "\t"
                << "0"
                << ",";
        outFile << std::endl;

        #endif
    }
    outFile.close();

    // 拷贝文件进行备份，文件以日期和时间为后缀
    if (!wxDir::Exists(wxT("./bak")))
    {
        wxDir::Make(wxT("./bak"));
    }

    // 增加备份文件
    char timeStr[128];
    time_t currentTime = time(NULL);
    strftime(timeStr, 128, "%Y-%m-%d-%H-%M-%S", localtime(&currentTime));
    wxCopyFile(fileName, wxString("./bak/fundinfo_").append(timeStr).append(".csv"), true);

    return true;
}

//设置基金确认文件路径
void mainFrame::setTaFileFromPath()
{
    ifstream infile;
    infile.open(FUNDROMEFILE, ios::in);
    if (!infile.is_open())
    {
        cout << FUNDROMEFILE << " is not fund" << endl;
        return;
    }

    string line;
    while(getline(infile,line))
    {
        //如果是已;开头的，直接跳过，为注释
		if(line.substr(0,1)==";" || line.substr(0,1)=="[")
		{
			continue;
		}

		//找到=位置，以=位置为基准去两边数据
		size_t pos = line.find("=");
		if (pos == std::string::npos)
		{
			continue;
		}

        string keyName = line.substr(0, pos);
        string valueStr = line.substr(pos+1);
        m_Settings.insert(pair(keyName, valueStr));
        
    }
    
    infile.close();
        
}

//初始化事件
void mainFrame::initEvent()
{
        // 设置输入框删除空格
        Bind(wxEVT_TEXT, &mainFrame::onFundCodeInput, this, TEXT_CTRL_FUND_CODE_INPUT_ID, TEXT_CTRL_FUND_CODE_INPUT_ID);
        Bind(wxEVT_TEXT, &mainFrame::onFundNameInput, this, TEXT_CTRL_FUND_NAME_INPUT_ID, TEXT_CTRL_FUND_NAME_INPUT_ID);

        //基金代码框输入ENTER添加基金
        Bind(wxEVT_TEXT_ENTER, &mainFrame::onAddfundPlus, this, TEXT_CTRL_FUND_CODE_INPUT_ID, TEXT_CTRL_FUND_CODE_INPUT_ID);

        // 空间大小事件
        Bind(wxEVT_SIZE, &mainFrame::onSizeEvent, this);

        // 绑定按钮事件
        Bind(wxEVT_BUTTON, &mainFrame::onAddfund, this, BTN_ADD_FUND_ID, BTN_ADD_FUND_ID);
        Bind(wxEVT_BUTTON, &mainFrame::onClearFund, this, BTN_CLEAR_FUND_ID, BTN_CLEAR_FUND_ID);
        Bind(wxEVT_BUTTON, &mainFrame::onExportFund, this, BTN_EXPORT_FUND_ID, BTN_EXPORT_FUND_ID);
}

//处理基金名称
void mainFrame::dealFundName(wxString &name)
{
        name.Replace("灵活配置", "");
        name.Replace("证券投资基金", "");
        name.Replace("混合型", "");
        name.Replace("发起式", "");
        name.Replace("联接", "");
        name.Replace("持有", "");
        name.Replace("混合", "");
        name.Replace("基金中基金", "");
        name.Replace("指数发起", "");
        name.Replace("指数增强发起", "");
        if (name.length() > 39)
                name = name.SubString(0, 39);
}

//升级版
void mainFrame::onAddfundPlus(wxCommandEvent & event)
{
        event.Skip();
        wxString tfundCode = m_textCtrlFundCode->GetLineText(0).Trim();
        wxStringTokenizer tokenizer(tfundCode, ",");
        wxArrayString errFunds; 

        while (tokenizer.HasMoreTokens())
        {
            wxString token = tokenizer.GetNextToken();
            if(token.Trim().length()==0)
            continue;
            addFundSingal(token,errFunds);
        }

        // 清空输入框，等待下一次输入
        m_textCtrlFundCode->Clear();
        m_textCtrlFundName->Clear();
        m_textCtrlFundCode->SetFocus();

        if (errFunds.size() == 0)
                return;

        // 输出未录入参数
        wxString fileName = wxT("./err/notsetfund.txt");
        std::string csvFileName = "./err/notsetfund.txt";

        if (!wxDir::Exists(wxT("./err")))
        {
                wxDir::Make(wxT("./err"));
        }
        std::ofstream errFile;
        errFile.open("./err/notsetfund.txt", std::ios::out);
        if (errFile.fail())
        {
                wxMessageBox(wxT("OTC文件导出失败\n\n notsetfund.txt文件打开失败"), wxT("CSV文件导出"), wxOK | wxICON_ERROR);
        }
        errFile << "请手工设置下列基金" << std::endl;
        for (auto &item : errFunds)
        {
                errFile << item.ToStdString() << std::endl;
        }        
        wxMessageBox(wxT("存在未导出的基金\n\n 请查看err/notsetfund.csv"), wxT("基金导出"), wxOK | wxICON_ERROR);
        errFile.close();
}

//单次增加基金
void mainFrame::addFundSingal(wxString &fund,wxArrayString & errFunds)
{
        wxString tfundCode = fund;        

        // 验证基金代码是否为数字和字母
        const char *charFundCode = tfundCode.c_str();
        for (size_t i = 0; i < strlen(charFundCode); i++)
        {
                if (int(charFundCode[i]) < 48 || int(charFundCode[i]) > 90)
                {
                        wxString msg;
                        msg << tfundCode;
                        msg << ":";
                        msg << wxT("输入的基金代码不为字母或数字");
                        errFunds.push_back(msg);
                        return;
                }
                if (int(charFundCode[i]) > 57 && int(charFundCode[i]) < 65)
                {
                        wxString msg;
                        msg << tfundCode;
                        msg << ":";
                        msg << wxT("输入的基金代码不为字母或数字");
                        errFunds.push_back(msg);
                        return;
                }
        }

        Fund tempfund;
        memset(&tempfund, 0, sizeof(tempfund));

        // 设置代码
        strncpy(tempfund.fund_code, tfundCode.c_str(), 8);

        // 检查基金是否已经存在
        for (auto it = m_Funds.begin(); it != m_Funds.end(); it++)
        {
                if (strcmp(it->fund_code, tempfund.fund_code) == 0)
                {                        
                        wxString msg;
                        msg << tfundCode;
                        msg << ":";
                        msg << wxT("输入的基金代码已存在");
                        errFunds.push_back(msg);
                        return;
                }
        }

        wxString tempGridFundName; // 表格基金名称
        wxCSConv enCoder(wxFONTENCODING_CP936);

        //自动获取基金参数及基金信息
        if (m_choiceTa->GetCurrentSelection() == 0)
        {
                // 取基金名称
                auto T_07itor = m_M07Funds.find(tfundCode.ToStdString());
                if (T_07itor != m_M07Funds.end())
                {
                        // 对基金名称进行处理，删除多余字符，仅保留简称
                        tempGridFundName = wxString(T_07itor->second.c_str(), enCoder);
                        dealFundName(tempGridFundName);
                        strncpy(tempfund.fund_name, tempGridFundName.ToStdString().c_str(), sizeof(tempfund.fund_name) - 1);
                }
                else
                {
                        // wxMessageBox(wxT("基金信息文件(07)中没有找到该基金，请通过手工维护"), wxT("错误信息"), wxOK | wxICON_ERROR);
                        wxString msg;
                        msg << tfundCode;
                        msg << ":";
                        msg << wxT("基金信息文件(07)中没有找到该基金，请通过手工维护");
                        errFunds.push_back(msg);
                        return;
                }

                // 取基金参数
                auto T_c2itor = m_Mc2Funds.find(tfundCode.ToStdString());
                if (T_c2itor != m_Mc2Funds.end())
                {
                        // 取TA代码
                        strncpy(tempfund.ta_code, T_c2itor->second.ta_code.c_str(), sizeof(tempfund.ta_code) - 1);
                        // 取OTC交收信息
                        tempfund.otc_fh_date = T_c2itor->second.fh + 1;
                        tempfund.otc_sh_date = T_c2itor->second.sh + 1;
                        // 取法人参数ID
                        int index = 0;
                        bool contentFlag = false;
                        for (auto &item : m_Parse)
                        {

                                if ((item.xy_fh_date == T_c2itor->second.fh) && (item.xy_sh_date == T_c2itor->second.sh))
                                {
                                        contentFlag = true;
                                        break;
                                }
                                index++;
                        }
                        if (contentFlag)
                        {
                                strncpy(tempfund.parse_id, m_Parse[index].parse_id.c_str(), sizeof(tempfund.parse_id) - 1);
                        }
                        else
                        {
                                
                                wxString msg;
                                msg << tfundCode;
                                msg << ":";
                                msg << wxT("参数模板中没有赎回");
                                msg << T_c2itor->second.sh;
                                msg << wxT("分红");
                                msg << T_c2itor->second.fh;
                                msg << wxT("的模板，请手工维护");
                                errFunds.push_back(msg);                                
                                return;
                        }
                }
                else
                {
                        // wxMessageBox(wxT("基金信息文件(C2)中没有找到该基金，请通过手工维护"), wxT("错误信息"), wxOK | wxICON_ERROR);
                        wxString msg;
                        msg << tfundCode;
                        msg << ":";
                        msg << wxT("基金信息文件(C2)中没有找到该基金，请通过手工维护");
                        errFunds.push_back(msg);
                        return;
                }
        }
        else    //手工设置基金参数和基金TA
        {
                // 设置基金TA
                strncpy(tempfund.ta_code, m_Tas[m_choiceTa->GetCurrentSelection()].code.c_str(), sizeof(tempfund.ta_code) - 1);

                // 设置基金名称
                tempGridFundName = m_textCtrlFundName->GetLineText(0);
                if (tempGridFundName.length() == 0)
                {
                        wxMessageBox(wxT("基金名称为空,请重新输入"), wxT("提示信息"), wxOK | wxICON_ERROR, this);
                        m_textCtrlFundName->SetFocus();
                        return;
                }

                // 对基金名称进行处理，删除多余字符，仅保留简称
                dealFundName(tempGridFundName);
                strncpy(tempfund.fund_name, tempGridFundName.ToStdString().c_str(), sizeof(tempfund.fund_name) - 1);

                // 检查TA
                if (!fundCheck(tempfund.ta_code, tempfund.fund_name, m_checkInfos))
                {
                        wxString mes;
                        mes.append("基金名称:【");
                        mes.append(tempfund.fund_name);
                        mes.append("】和TA代码:【");
                        mes.append(tempfund.ta_code);
                        mes.append("】可能不匹配，是否继续添加?");
                        auto res = wxMessageBox(mes, wxT("提示信息"), wxYES_NO | wxICON_QUESTION, this);
                        if (res == wxNO)
                                return;
                }

                // 设置基金参数
                strncpy(tempfund.parse_id, m_Parse[m_choiceParse->GetCurrentSelection()].parse_id.c_str(), sizeof(tempfund.parse_id) - 1);
                tempfund.otc_fh_date = m_Parse[m_choiceParse->GetCurrentSelection()].xy_fh_date + 1;
                tempfund.otc_sh_date = m_Parse[m_choiceParse->GetCurrentSelection()].xy_sh_date + 1;
        }

        m_Funds.push_back(tempfund);

        m_gridFundData->AppendRows();
        auto rowNum = m_gridFundData->GetNumberRows();

        m_gridFundData->SetCellValue(rowNum - 1, 0, getFullTaName(&m_Tas[m_choiceTa->GetCurrentSelection()]));
        m_gridFundData->SetCellValue(rowNum - 1, 1, tempfund.fund_code);
        m_gridFundData->SetCellValue(rowNum - 1, 2, tempGridFundName); // 定义tempGridFundName修复显示问题
        m_gridFundData->SetCellValue(rowNum - 1, 3, wxString::Format("%i", tempfund.otc_sh_date - 1));
        m_gridFundData->SetCellValue(rowNum - 1, 4, wxString::Format("%i", tempfund.otc_fh_date - 1));

        // 如果是自动获取参数，更新TA代码
        if (m_choiceTa->GetCurrentSelection() == 0)
        {
                string taFullName = tempfund.ta_code;
                for (auto item : m_Tas)
                {
                        if (item.code == taFullName)
                                taFullName = getFullTaName(&item);
                }
                m_gridFundData->SetCellValue(rowNum - 1, 0, taFullName);
        }

        m_gridFundData->SetRowSize(rowNum - 1, 35);

        // 设置滚动条自动滚动至最后
        if (!m_gridFundData->IsVisible(rowNum - 1, 0))
        {
                m_gridFundData->ScrollLines(rowNum);
        }
}